package main

import (
	"context"
	"fmt"
	"log"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var users *mongo.Collection
var client *mongo.Client

func init() {
	var err error
	clientOpt := options.Client() //
	uri := "mongodb://localhost:27017/"

	// 设置认证信息
	credential := options.Credential{
		Username: "admin",
		Password: "123456",
		// 如果需要指定认证数据库（如果用户不是在admin库中创建的）
		// AuthSource: "admin",
	}
	clientOpt.SetAuth(credential)

	// loggerOpt := options.Logger()
	// loggerOpt.SetComponentLevel(options.LogComponentCommand, options.LogLevelDebug)
	// clientOpt.SetLoggerOptions(loggerOpt)
	clientOpt.ApplyURI(uri)
	client, err = mongo.Connect(context.TODO(), clientOpt) // URI
	if err != nil {
		log.Fatal(err)
	}
	err = client.Ping(context.TODO(), nil)
	if err != nil {
		log.Fatal(err, "###")
	}
	fmt.Println(client)
	// 指定库、表
	db := client.Database("test")
	users = db.Collection("users") // 表 Table collection 集合 打开了 test 库里的 users 表
}

type User struct {
	// 主键，没有提供的话，会生成一个主键_id
	Id   primitive.ObjectID `bson:"_id,omitempty"` // [12]byte
	Name string
	Age  int
}

func (u User) String() string {
	return fmt.Sprintf("<User %v: %s, %d>", u.Id, u.Name, u.Age)
}

func FindOne() {
	// 查询条件
	filter := bson.D{}
	// filter = bson.D{bson.E{Key: "yam", Value: 31}}
	// filter = bson.D{bson.E{"yam", 31}}
	filter = bson.D{{"age", 31}}

	sr := users.FindOne(context.TODO(), filter)
	fmt.Println(sr.Raw())
	fmt.Println(sr.Err())
	// var i any
	// err := sr.Decode(&i)
	// fmt.Println(err, "####")
	// fmt.Printf("%T %+[1]v\n", i)
	var u User
	err := sr.Decode(&u)
	fmt.Println(err, "####")
	fmt.Printf("%T %+[1]v \n", u)
}

func FindMany() {
	filter := bson.D{}
	cursor, err := users.Find(context.TODO(), filter)
	// cursor游标，返回的结果集中的某一行的数据
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(context.TODO())
	var us []*User
	for cursor.Next(context.TODO()) {
		// fmt.Println(cursor.Current)
		var u User
		err := cursor.Decode(&u)
		if err != nil {
			continue
		}
		us = append(us, &u)
	}
	fmt.Println(us)
}

func FindMany2() {
	filter := bson.D{}
	FindByFilter(filter)
}
func FindByFilter(filter any) {
	FindAll(filter, nil)
}

func FindAll(filter any, opt *options.FindOptions) {
	cursor, err := users.Find(context.TODO(), filter, opt)
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(context.TODO())
	var us []*User
	err = cursor.All(context.TODO(), &us)
	if err != nil {
		log.Fatal(err)
	}
	for _, u := range us {
		fmt.Println(*u)
	}
}

func main() {
	defer func() {
		if err := client.Disconnect(context.TODO()); err != nil {
			log.Fatal(err)
		}
	}()
	filter := bson.M{}
	opt := options.Find()
	opt.SetProjection(bson.M{"name": true})              // id一定有
	opt.SetProjection(bson.M{"name": true, "age": true}) // id一定有

	opt.SetSort(bson.M{"name": 1}). // 单字段排序
					SetLimit(3).SetSkip(4) // 分页
	FindAll(filter, opt)

}
